package ClientPackage;
/**
 * @(#)client.java
 *
 *
 * @author 
 * @version 1.00 2014/2/28
 */
import java.io.*;
import java.net.*;
import java.awt.*;
import java.util.*;   
import javax.swing.*;
import java.awt.event.*;
import javax.sound.sampled.*;

public class Client {
        
    private InetAddress inetaddress; /* */
    private String address=null; /* */
    private Socket socket=null; /* */
    private String message=null; /* */
    private JOptionPane optionpane; /* */
    private PrintWriter lineout; /* */
    private JTextArea textarea; /* */
    private JFrame frame; /* */
    private JTextField textfield; /* */
    private String name="Client"; /* */
    private JButton downloadButton; /* */
    private JButton uploadButton; /* */
    private JButton chatButton; /* */
    private JButton voiceChatButton; /* */
    private AudioFormat audioFormat; /* */
  	private TargetDataLine targetDataLine; /* */
  	private double duration,second; /* */
	private AudioInputStream soundAudioInputStream; /* */
  	private String errStr; /* */
  	private int bufSize = 16384; /* */
    private AudioFormatControl formatControls = new AudioFormatControl(); /* */
    private Playback playback = new Playback(); /* */
    private AudioCapture capture = new AudioCapture(); /* */
    private boolean record=false; /* */
    private TargetDataLine line; /* */
    private int UserConnectionPointer=1; /* */
    private JFileChooser filechoose; /* */
    private File file; /* */
    private StringTokenizer stringtokenizer; /* */
    private String file_info = null; /* */
    private boolean download = false; /* */
    private boolean upload = false; /* */
    private BufferedReader inline; /* */
    private JTable table; /* */
    private String saveFileName = "record"; /* */
    Thread Audiocapturethread = new Thread(capture);  /* */

    public Client() {
    	
    	System.out.println("running client..");
    	name = optionpane.showInputDialog(new JFrame(),"Enter your name");

    	message = optionpane.showInputDialog(new JFrame(),
                "Enter the servers local address",
                "fe80:0:0:0:3d4c:f171:c327:d8bb%23");
        
    	connect();
    	
    }
    public void connect(){
    
    	try{
    		socket = new Socket(message,3333);
            address = message;
            System.out.println("client socket: "+ socket);
            
    		inline = new BufferedReader(new InputStreamReader(
                    socket.getInputStream()));
    		lineout = new PrintWriter(socket.getOutputStream(), true);

    		showGui();
    		System.out.print("initialize actionlistener");
    		actionlistener();
            while((message=inline.readLine())!=null){
                    System.out.println("current message: "
                                        +message +" length "+message.length());


                    if(message.equals(name+":save")){
                        System.out.println("saving file");
                        saveSoundFile();
                    }
                    //check messages before appending in the textarea
                    if(message.equals("null")){
                        System.out.println("null message");
                       message="";
                    }
                    
                    if(message.equals(name+":play")){
                        System.out.println("playing audio..");
                        new Thread(new Playback()).start();
                        }
                    else if(message.equals("downloadfile")){
                        System.out.println("downloadfile request");
                        message="";
                        file_info = inline.readLine();
                         new Thread(new downloadFile()).start();
                        
                        }
                    message.trim();
                    textarea.append(message+'\n');
    	       }
    	   }
    	catch (Exception e){
            System.out.println("connection error "+e 
                                +" message " + message);
            // create anoher runnable class with diffrent port  for file upload/download
            //System.exit(0);
        }

    }
    public void showGui(){
    	System.out.println("initialize Gui");
    		textarea = new JTextArea();
    		textfield = new JTextField();
    		frame = new JFrame("Client");
    		frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
    		downloadButton = new JButton("add file");
            chatButton = new JButton("Chat");
            voiceChatButton = new JButton("voiceChat");
            uploadButton = new JButton("Upload");
            frame.setLayout(new GridLayout(2,1));
            JPanel panel = new JPanel();
            System.out.println("adding panel component");
            filechoose = new JFileChooser();
            panel.add(downloadButton);
            panel.add(uploadButton);
            panel.add(chatButton);  
    		panel.add(voiceChatButton);	
            System.out.println("adding panel in the frame");
    		frame.add(panel);
            JPanel panel2 = new JPanel();
            panel2.setLayout(new GridLayout(2,1));
    		panel2.add(new JScrollPane(textarea));
    		panel2.add(textfield);
            frame.add(panel2);
    		frame.setSize(300,390);
            System.out.println("set frame visible");
    		frame.setVisible(true);
    }
  
    public void actionlistener(){

    		textfield.addActionListener(new ActionListener(){
      		    public void actionPerformed(ActionEvent event) {

                String strtext = textfield.getText();

                    strtext.trim();

                    if(strtext.equals("")){
                        return;
                    }
                    else if (strtext.equals(null)){
                        return;
                    }
                    else{

                        lineout.println(name+":" + strtext);
                        lineout.println(UserConnectionPointer);
                        textfield.setText(""); 
                    }
     			    }
                });

             uploadButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                System.out.println("uploadButton listener");
                try{

					 int retrnValue = filechoose.showOpenDialog(null);
           			 if (retrnValue == JFileChooser.APPROVE_OPTION) {
                		file = filechoose.getSelectedFile();
            			}
                 new Thread(new uploadFile()).start();
                }
                catch (Exception e){
                    System.out.println("uploadButton action listener error "+ e);
                    }       
                }  
            });
             downloadButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                System.out.println("downloadButton listener");
                try{

                    //System.out.println("starting uploadfile class..");
                   // new Thread(new uploadFile()).start();
                lineout.println("downloadfile");// sends the desired filename
                System.out.println("Sending UserConnectionPointer");
                lineout.println(UserConnectionPointer);

                lineout.println("mychoosenfileisblahlblah");
                }
              catch (Exception e){
                    System.out.println("action listener error "+ e);
                    }   
                }
            });

            voiceChatButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                System.out.println("voiceChatButton listener");
                try{
                     if(voiceChatButton.getText().equals("voiceChat")){
                        voiceChatButton.setText("End");
                        record=true;
                      //  voiceChat();
                      Audiocapturethread.start();
                        System.out.println("Chatting");
                    }
                    else{
                        voiceChatButton.setText("voiceChat");
                        System.out.println("closing chat");
                        Audiocapturethread=null;
                      // 	audiocapturethread.stop();
                    //  Capture
                        System.out.println("recored"+ record);
                    //    line.stop();
                      //  line.close();
                        //line=null;
                    }
                }   
                catch (Exception e){
                    System.out.println("voiceChatButton action listener error "+ e);
                    }       
                }
            });
        }
    
    public void voiceChat(){
        new Thread(new AudioCapture()).start();
        }

    public class AudioCapture implements Runnable {
       
     
        public void run() {
        
            duration = 0;
            soundAudioInputStream = null;
            
            // define the required attributes for our line, 
            // and make sure a compatible line is supported.

            AudioFormat format = formatControls.getFormat();
            DataLine.Info info = new DataLine.Info(TargetDataLine.class,format);
                        
            if (!AudioSystem.isLineSupported(info)) {
                System.out.println("Line matching " + info + " not supported.");
                return;
            }

            // get and open the target data line for capture.

            try {
                line = (TargetDataLine) AudioSystem.getLine(info);
                line.open(format, line.getBufferSize());
            } catch (LineUnavailableException ex) { 
              System.out.println("cant open the line "+ex.toString());
                return;
            } catch (SecurityException ex) { 
				System.out.println(""+ex.toString());
                return;
            } catch (Exception ex) { 
                System.out.println(ex.toString());
                return;
            }
			System.out.println("playback the captured audio data");
            // play back the captured audio data
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int frameSizeInBytes = format.getFrameSize();
            int bufferLengthInFrames = line.getBufferSize() / 8;
            int bufferLengthInBytes = bufferLengthInFrames * frameSizeInBytes;
            byte[] data = new byte[bufferLengthInBytes];
            int numBytesRead=0;
            
            line.start();
			
            while(Audiocapturethread!=null) {
                if((numBytesRead = line.read(data, 0, bufferLengthInBytes)) == -1) {
                    break;
               		}
               
               	System.out.println("audiorecording...");
                out.write(data, 0, numBytesRead);
            }

            if(Audiocapturethread!=null){
                line.drain();
            }
            // we reached the end of the stream.  stop and close the line.
            System.out.println("line stopped");
            line.stop();
            line.close();
            line = null;

            // stop and close the output stream
            try {
                out.flush();
                out.close();
            } catch (IOException ex) {
                ex.printStackTrace();
                System.out.println("io Exception: "+ ex);
            }

            // load bytes into the audio input stream for playback
			System.out.println("audio capture: autdioInputstream..");
            byte audioBytes[] = out.toByteArray();
            ByteArrayInputStream bais = new ByteArrayInputStream(audioBytes);

            soundAudioInputStream = new AudioInputStream(bais, format, 
                                audioBytes.length / frameSizeInBytes);

            long milliseconds = (long)((soundAudioInputStream.getFrameLength() 
                                * 1000) / format.getFrameRate());

            duration = milliseconds / 1000.0;
			System.out.println("done audio capturing");
            try {
                soundAudioInputStream.reset();
            } catch (Exception ex) { 
                ex.printStackTrace(); 
                return;
            }
        }
    }
    public void saveSoundFile(){
        saveFileName = JOptionPane.showInputDialog(frame,"Enter save name");
        saveFileName = saveFileName+".wav";
        saveRecordedSoundToFile(saveFileName, AudioFileFormat.Type.WAVE);
    }
    public class Playback implements Runnable {

         Thread thread=new Thread();

        public void stop() {
            thread = null;
        }
        
        public void run() {
            SourceDataLine line;
           
            // make sure we have something to play
            if (soundAudioInputStream == null) {
              System.out.println("audioInoutStream=null");
              return;
            }
            // reset to the beginnning of the stream
            try {
                soundAudioInputStream.reset();
            } catch (Exception e) {
            	System.out.println("error 12 "+ e);
                return;
            }

            // get an AudioInputStream of the desired format for playback
            System.out.println("getting format..");
            AudioFormat format = formatControls.getFormat();
            AudioInputStream playbackInputStream = 
                AudioSystem.getAudioInputStream(format, soundAudioInputStream);
                        
            if (playbackInputStream == null) {
                System.out.println("playbackInputStream error" + soundAudioInputStream + " to format " + format);
                return;
            }

            // define the required attributes for our line, 
            // and make sure a compatible line is supported.

              System.out.println("checking the format..");

            DataLine.Info info = new DataLine.Info(SourceDataLine.class, 
                format);
            if (!AudioSystem.isLineSupported(info)) {
					System.out.println("Line matching " + info + " not supported.");
                return;
            }

            // get and open the source data line for playback.

            try {
                line = (SourceDataLine) AudioSystem.getLine(info);
                line.open(format, bufSize);
            } catch (LineUnavailableException ex) { 
				System.out.println("Unable to open the line: " + ex);
                return;
            }

            // play back the captured audio data

            int frameSizeInBytes = format.getFrameSize();
            int bufferLengthInFrames = line.getBufferSize() / 8;
            int bufferLengthInBytes = bufferLengthInFrames * frameSizeInBytes;
            byte[] data = new byte[bufferLengthInBytes];
            int numBytesRead = 0;

            // start the source data line
            line.start();
            System.out.println("starting the line...");
            while (thread != null) {
                try {
                    if ((numBytesRead = playbackInputStream.read(data)) == -1) {
                        System.out.println("bytes=-1");
                        break;
                    }
                    System.out.println("Reading the line..");
                    int numBytesRemaining = numBytesRead;
                    while (numBytesRemaining > 0 ) {
                        numBytesRemaining -= line.write(data, 0, numBytesRemaining);
                    }
                } catch (Exception e) {
                   System.out.println("Error during playback: " + e);
                    break;
                }
            }
            // we reached the end of the stream.  let the data play out, then
            // stop and close the line.
            if (thread != null) {
                System.out.println("drainning the line");
                line.drain();
            }
            
            line.stop();
            line.close();
            line = null;
            System.out.println("line is stopped and closed");
        }
    } // End class Playback	

    /**
     * Controls for the AudioFormat.
     */
   public class AudioFormatControl{
        public AudioFormat getFormat() {

             /*Default encoding and audio format*/
            AudioFormat.Encoding encoding = AudioFormat.Encoding.PCM_SIGNED;
           
            String encString 	= "linear";
            float rate 			= 44100;
            int sampleSize 		= 16;
            String signedString = "signed";
            boolean bigEndian 	= true;
            int channels 		= 2;

            return new AudioFormat(encoding, rate, sampleSize, 
                          channels, (sampleSize/8)*channels, rate, bigEndian);
        }
    } 

    public void fileChooser(){
        try{
            int retrnValue = filechoose.showOpenDialog(null);
            if (retrnValue == JFileChooser.APPROVE_OPTION) {
                file = filechoose.getSelectedFile();
            }
          //  outputstream[UserConnectionPointer].println("New incoming file, Click Accept Button to confirm "+'\n');
            new Thread(new uploadFile()).start(); 
        }
        catch(Exception e){
            System.out.println("2 Sending File Error: "+e);
        }
     }
    /**
     * 
     */
    public class uploadFile implements Runnable{ // upload file
        public void run(){
        try {

           UserConnectionPointer=1;
          //  if(UserConnectionPointer!=0){

                int port=0;
                System.out.println("getting local port");
                port = socket.getLocalPort();
             
                /**/
                System.out.println("Sending signal");
                lineout.println("uploadFile");
                lineout.println(UserConnectionPointer);
              

                long filesize;
                filesize = file.length();

                lineout.println(file.getName()+","+filesize+","
                                +UserConnectionPointer+","+socket.getLocalPort());

                Socket filesocket;

                filesocket = new Socket(address,2233);

               // UserConnectionPointer=0;//temporary 

        

                System.out.println("new file copy..."); 
                System.out.println("waiting for receiver.....");
                System.out.println("Accepted connection : " + socket);
            
                byte [] bytearray  = new byte [(int)file.length()];

                FileInputStream fin = new FileInputStream(file);

                BufferedInputStream bin = new BufferedInputStream(fin);
        
                bin.read(bytearray,0,bytearray.length);
                OutputStream os = filesocket.getOutputStream();
                System.out.println("Sending File...");
                os.write(bytearray,0,bytearray.length);
                os.flush();
                filesocket.close();
                System.out.println("File upload complete");
                }
    // if con=0 ..   }
            catch (IOException e) {
               System.out.println("Sending file error: " +e);    
        }
        }
    } // end of uploadFile class  
    public  class  downloadFile implements Runnable{
        public void run(){
        try{

             
            System.out.println("getting file info...");
            int filesize;
            int bytesRead;
            int currentTot = 0;
            String file_information=null;
            int port = 0;
            file_information = file_info; // temporary
            System.out.println("Sending signal");
            String filename;
            
            
            System.out.println("setting StringTokenizer");
           
            stringtokenizer = new StringTokenizer(file_information.trim(),",");
            System.out.println("file info: " + file_information);
              
            filename = stringtokenizer.nextToken();
            System.out.println("getting filename: " + file_information);

            filesize = Integer.parseInt(stringtokenizer.nextToken());

            UserConnectionPointer = Integer.parseInt(stringtokenizer.nextToken());
            port = Integer.parseInt(stringtokenizer.nextToken());

            port = 2222; // for the mean time only.. 

        
            Socket fileDownloadSocket = new Socket(address,port); 

            System.out.println("userConnectionPointer: "+UserConnectionPointer);

               
            System.out.println("file socket " + fileDownloadSocket);
                
            filesize= filesize*2;
            byte [] bytearray  = new byte [filesize];
            InputStream is = fileDownloadSocket.getInputStream();
            FileOutputStream fos = new FileOutputStream(filename);
            BufferedOutputStream bos = new BufferedOutputStream(fos);
            bytesRead = is.read(bytearray,0,bytearray.length);
            currentTot = bytesRead;
            System.out.println("reading input");

            do {
               bytesRead =
               is.read(bytearray, currentTot, (bytearray.length-currentTot));
               if(bytesRead >= 0) currentTot += bytesRead;
                } while(bytesRead > -1);

                bos.write(bytearray, 0 , currentTot);
                bos.flush();
                bos.close();
                is.close();
                fileDownloadSocket.close();
                System.out.println("file download complete "+ filename);
                }
                catch (Exception e){
                   System.out.println("file download file error: "+ e);
                   download=false;
                }
            } 
        }
     public void saveRecordedSoundToFile(String name, AudioFileFormat.Type fileType) {

        System.out.println("saving record");
        if (soundAudioInputStream == null) {
            System.out.println("No loaded audio to save");
            return;
        } else if (file != null) {
            System.out.println("file != null.. must "
                    + " create new  createAudioInputStream file");
            System.out.println("The file is not empty");
        }

        // reset to the beginnning of the captured data
        try {
            soundAudioInputStream.reset();
        } catch (Exception e) { 
            System.out.println("Uanble to reset the stream " + e);
           // reportStatus("Unable to reset stream " + e);
            return;
        }

        File file = new File(saveFileName = name);
             System.out.println("writng audio file.......");
        try {
            if (AudioSystem.write(soundAudioInputStream, fileType, file) == -1) {
                throw new IOException("Problems writing to file");
            }
        } 
        catch (Exception ex) {
            System.out.println("status " + ex.toString());
           // reportStatus(ex.toString()); 
            }
        System.out.print("ok");
    }
        
    public static void main(String[] args) {
        new Client();
    }
}
